#include "meter.h"
#include <sqlite3.h>
#include <stdio.h>
#include <time.h>
#include <syslog.h>


/** 
 * Callback function used by sqlite3 database functions
 */
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
  int i;
  syslog(LOG_INFO, "Callback\n");
  for(i=0; i<argc; i++){
    syslog(LOG_INFO, "%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
  }
  syslog(LOG_INFO, "\n");
  return 0;
}

/**
 * Write the current reading of meter number i to the database
 *
 * 07FEB2006  GJ  ORIGINAL VERSION
 * 21mar2008  GJ  Added id column to readings table and changed time
 *                 format to SQL date/time rather than integer.
 * 13apr2008  GJ  Changed so that the meter id number is not the same as the array index no.
 */
int db_write_data(int i) {
  int rc;
  sqlite3 *db;
  char *zErrMsg = 0;
  char SQLstr[256];
  struct tm *tms;

  syslog(LOG_INFO, "Opening Database\n");
  rc = sqlite3_open(DBFILE,&db);
  if( rc ){
    syslog(LOG_ERR, "Can't open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    exit(1);
  }

  /* Save the meter reading to the 'readings' table. */
  tms = localtime(&meters[i].last_output);
  sprintf(SQLstr,"insert into readings (meter, time, reading) values( %d, \'%04d-%02d-%02d %02d:%02d:%02d\' , %10.3lf);",
	  meters[i].id,
	  1900+tms->tm_year, 1+tms->tm_mon, tms->tm_mday,
	  tms->tm_hour, tms->tm_min, tms->tm_sec,
	  meters[i].reading);
  syslog(LOG_INFO, "Calling sqlite3_exec - SQL=\"%s\"..\n",SQLstr);
  rc = sqlite3_exec(db,SQLstr, callback, 0, &zErrMsg);
  if( rc!=SQLITE_OK ){
    syslog(LOG_ERR, "SQL error: %s\n", zErrMsg);
  }

  /* Save the meter reading to the meters table */
  sprintf(SQLstr,"update meters set reading=%10.3lf where id=%d;",
	  meters[i].reading,meters[i].id);
  syslog(LOG_INFO, "Calling sqlite3_exec - SQL=\"%s\"..\n",SQLstr);
  rc = sqlite3_exec(db,SQLstr, callback, 0, &zErrMsg);
  if( rc!=SQLITE_OK ){
    syslog(LOG_ERR, "SQL error: %s\n", zErrMsg);
  }

  sqlite3_close(db);
}

int db_list_meters(int i) {
  int rc;
  sqlite3 *db;
  char *zErrMsg = 0;
  syslog(LOG_INFO, "Opening Database\n");
  rc = sqlite3_open(DBFILE,&db);
  if( rc ){
    syslog(LOG_ERR, "Can't open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    exit(1);
  }
  syslog(LOG_INFO, "Calling sqlite3_exec..\n");
  rc = sqlite3_exec(db,"select * from meters", callback, 0, &zErrMsg);
  if( rc!=SQLITE_OK ){
    syslog(LOG_ERR,"SQL error: %s\n", zErrMsg);
  }
  else
    syslog(LOG_INFO, "Returned from sqlite3_exec ok\n");
  sqlite3_close(db);
}



/** 
 * Callback function used by db_initialise_meters() function.
 * Initialises the meters[] array and increments the count of the number
 * of meters, global variable n_meter;
 */
static int initialise_callback(void *NotUsed, int argc, char **argv, char **azColName){
  int i;
  int metno=-1;

  /* first get meter number */
  for(i=0; i<argc; i++){
    if (!strcmp(azColName[i],"id")) {
      sscanf(argv[i],"%d",&metno);
    }
  }
  if (metno>=0) {
    for(i=0; i<argc; i++){
      if (!strcmp(azColName[i],"id")) {
	sscanf(argv[i],"%d",&meters[n_meter].id);
      }
      if (!strcmp(azColName[i],"description")) {
	sscanf(argv[i],"%s",meters[n_meter].description);
      }
      if (!strcmp(azColName[i],"unit")) {
	sscanf(argv[i],"%s",meters[n_meter].unit);
      }
      if (!strcmp(azColName[i],"cfac")) {
	sscanf(argv[i],"%lf",&meters[n_meter].cfac);
      }
      if (!strcmp(azColName[i],"output_period")) {
	sscanf(argv[i],"%ld",&meters[n_meter].output_period);
      }
      if (!strcmp(azColName[i],"iocard")) {
	sscanf(argv[i],"%d",&meters[n_meter].iocard);
      }
      if (!strcmp(azColName[i],"input")) {
	sscanf(argv[i],"%d",&(meters[n_meter].input));
      }
      if (!strcmp(azColName[i],"reading")) {
	sscanf(argv[i],"%lf",&meters[n_meter].reading);
      }
      meters[n_meter].lastval = 0;
      meters[n_meter].last_output = 0;
    }
    n_meter ++;
  }
  else {
    syslog(LOG_ERR, "Error - Failed to read meter ID from database\n");
  }
    return 0;
}


/**
 * Initialise the meters[] array using data from the database
 * returns n_meter, the number of meters in the array, and also sets n_meter
 * as a global variable.
 *
 * 17 Feb 2006  GJ  ORIGINAL VERSION
 */
int db_initialise_meters() {
  int rc;
  int i;
  sqlite3 *db;
  char *zErrMsg = 0;

  rc = sqlite3_open(DBFILE,&db);
  if( rc ){
    syslog(LOG_ERR, "Can't open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    exit(1);
  }

  rc = sqlite3_exec(db,"select * from meters", initialise_callback, 0, &zErrMsg);
  if( rc!=SQLITE_OK ){
    syslog(LOG_ERR, "SQL error: %s\n", zErrMsg);
  }

  sqlite3_close(db);

  return n_meter;
}



/*
 * Writes the configuration data for meter number i to the database
 * 04mar2006  GJ  ORIGINAL VERSION
 * 21oct2006  GJ  Fixed some bugs in the SQL that stopped it working.
 * 13apr2008  GJ  Modified to separate the database id from the array index
 *                  so that the database ID an have any value.
 */
int db_save_meter_data(int i) {
  int rc;
  sqlite3 *db;
  char *zErrMsg = 0;
  char SQLstr[256];

  rc = sqlite3_open(DBFILE,&db);
  if( rc ){
    syslog(LOG_ERR, "Can't open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    exit(1);
  }

  /* Save the meter reading to the meters table */
  sprintf(SQLstr,"update meters set \n \
         description=\"%s\", \n \
         unit=\"%s\", \n \
         cfac=%lf, \n \
         reading=%10.3lf,  \n \
         output_period=%ld \n \
         where id=%d;",
	  meters[i].description,
	  meters[i].unit,
	  meters[i].cfac,
	  meters[i].reading,
	  meters[i].output_period,
          meters[i].id);
  rc = sqlite3_exec(db,SQLstr, callback, 0, &zErrMsg);
  sqlite3_close(db);
  if( rc!=SQLITE_OK ){
    syslog(LOG_ERR, "SQL error: %s\n", zErrMsg);
    return(-1);
  }

  return(0);
}
